/* 注1：字符串别忘记加引号*/
/* 注2：
    <!--
        当输入!后无法出现开头代码的时候，有2种解决办法，
            1.输入！后，再按一下tab键
            2.输入HTML:5，之后也会自动出现
            
    -->
*/
/* 注3：反引号可以让字符串换行，字符串模板的时候常用*/
// 注4：当外联CSS/JS失效的时候，引入CSS/JS文件的地址结尾加一个 ? ，之后再随意取一个名字=一个随意的数值
// p标签常用在段落上；h1等标签常用于标题标签；ul>li常用于导航栏；span标签常用于写无关紧要的东西，或者需要排版；strong标签用于针对于浏览器来讲是加强语气。


// 此函数输入的是  "#字符串" 和 ".字符串" 或者 标签名（字符串形式）
// 通过这个函数，可以省略  var 名=document.getElementById('id名')（或者class、tag） 这行代码
// 注意应用class、和tag的时候，它们是类数组，需要带上序号[num]
function $(ele1)
{
    var op = ele1.slice(0, 1)
    if (op == "#")
    {
        return document.getElementById(ele1.slice(1))
    }
    else if (op == ".")
    {
        if (document.getElementsByClassName)
        {
            return document.getElementsByClassName(ele1.slice(1))
        }
        else
        {
            var arr = []
            for (var i = 0; i < allNodes.length; i++)
            {
                if (allNodes[i].className.indexOf(ele1.slice(1)) != -1)
                {
                    arr.push(allNodes[i])
                }
            }
            return arr
        }
    }
    else
    {
        return document.getElementsByTagName(ele1)
    }
}


//求取数组最值
//函数第一个形参是数组；第二个形参是填字符串"min"或者"max"，字符串要加引号
function seek_extreme_value(arr,extreme)
{
    var M=arr[0]        //树立一个靶子
    if(extreme=="max")
    {
        for(var i=0;i<arr.length;i++)
        {
            if(M<arr[i])
            {
                M=arr[i]
            }
        }
        return M
    }
    else if(extreme=="min")
    {
        for(var i=0;i<arr.length;i++)
        {
            if(M>arr[i])
            {
                M=arr[i]
            }
        }
        return M                                                                                    
    }
    else
    {
        alert("第二个值只能输入字符串max或者min")
        delete array
    }
}
// 取出数组最大值也可以这么做，如果求最小值的话，就把max改成min
/*
function seek_max_value(arr)
{
    res = Math.max.apply('', arr)
    return res
}
*/


//求取某值是否在数组中，如果在就返回位次，否则返回-1；
//函数第一个形参是所寻找的值；第二个形参是数组
// 也可以用到数组属性中的  数组.search(项)  属性或者  数组.indexOf(项)  属性
function indexOf_array(value,arr)
{
    var k=-1
    for(var i=0;i<arr.length;i++)
    {
        if(value==arr[i])
        {
            k=i
        }
    }
    return k
}


//对原数列进行去重，并且返回去重之后的数列
//函数的形参是原始数列
//注意：此函数引用了indexOf_array(value,arr)函数
function remove_repeat(array)
{
    var k=[]
    for(var i=0;i<array.length;i++)
    {
        if(indexOf_array(array[i],k)==-1)
        {
            k.push(array[i])            //这么写运用了数组的应用属性
            // k[k.length]=array[i]     //这么写也可以，注意是k.length，这样保证了undefined不会出现，k[k.length]指又向后面加了一个值
            // k[i]=array[i]            这么写会有undefined出现
        }
    }
    return k
}


//求到设定时间的TIME值（字符串形式）为止的倒计时，即剩余时间
//函数的形参是设定时间，如"2022-07-09 18:30:09"，是字符串形式
function countdown(TIME)
{
    var a=[]
    setInterval(function()
    {
        var settime=new Date(TIME)
        var localtime=new Date()
        var derta=settime.getTime()-localtime.getTime()
        var sec=parseInt((derta/1000)%60)
        var minu=parseInt((derta/1000/60)%60)
        var ho=parseInt((derta/1000/3600)%24)
        if(sec<10&&sec>=0)
        {
            sec="0"+sec
        }
        if(minu<10&&minu>=0)
        {
            minu="0"+minu
        }
        if(ho<10&&ho>=0)
        {
            ho="0"+ho
        }
        if(ho<=0&&sec<=0&&minu<=0)
        {
            alert("时间到！")
            ho="00"
            minu="00"
            sec="00"
        }
        console.log(ho+":"+minu+":"+sec)
        a=[sec,minu,ho]
        console.log(a);
    },1000)
}


//对数组进行不去重或者去重之后的倒序排列
//函数的第一个形参是原来的数列，第二个参数只能输入字符串repeat（不去重）或者no_repeat（去重）
//注：去重之后的倒序排列引用了remove_repeat(array)函数
//直接用reverse()函数也一样
//如果是用字符串倒置，则是用split()先转化成数组，之后用reverse()函数，最后再用join()重新转化为字符串
//***************************
function reverse_order(arr,repeat)
{
    var op=[]
    if(repeat=="repeat")
    {
        for(var i=0;i<arr.length;i++)
        {
            op[i]=arr[arr.length-1-i]
        }
    }
    else if(repeat=="no_repeat")
    {
        opp=remove_repeat(arr)

        for(var i=0;i<opp.length;i++)
        {
            op[i]=opp[opp.length-1-i]
        }
    }
    else
    {
        alert("第二个参数只能输入字符串repeat或者no_repeat")
        delete op
    }
    return op
}


//对用符号连接的字符串的首字母大写，其他字母小写
//函数的第一个形参是原来的字符串；第二个形参是原来字符串中，连接字符串所用的符号，需要用" "括上；第三个形参是最后得到的字符串中，连接字符串所用的符号，也需要用" "括上
//***************************
function capitalize_after_symbol(arr,symbol_1,symbol_2)
{
    var mid=[]                                           //定义mid空数组是用来接收原来的字符串转化而来的数列
    mid=arr.split(symbol_1)                              //转化成为数列，并将symbol字符化成逗号
    var res=[]                                           //res用来储存新数组
    for(var i=0;i<mid.length;i++)                        //用mid.length的原因：定好新数组中字符串的个数
    {
        res[i]=mid[i].charAt(0).toUpperCase()            //先把数组中每一项字符串的第一个字符变大写之后原样加上去就行
        for(var j=1;j<arr.length;j++)                    //用arr.length的原因：保证把数组中每一项字符串中的每一个字符，都能放入新的数组中的每一项字符串
        {
            res[i]=res[i]+mid[i].charAt(j).toLowerCase() //对每一项都开始从第j项依次变成小写字母后正常拼接
        }
    }                                                    //注意，前面两行中的res[i]不能变成res[i].charAt[j]，这么写是错误的。因为对于长度是m的字符串，无法像是数组那样定义arr.charAt(m+1)=字符，这样不符合语法规则。
        // 注意：
        // for(var i=0;i<u.length;i++)
        // {
        //     y[i]=u[i].charAt(0).toUpperCase()+u[i].slice(1,str.length)
        // }
        //利用字符串的slice命令（数组中的slice命令也是类似）也可以简化代码，201-208行可以简化成这样
    res=res.join(symbol_2)                               //用数组的join命令，自动把数组转化为字符串，并且用什么symbol字符就写什么symbol字符即可
    return res
}


//获取当前时间，并显示在表盘上，调用时需要把“模拟时钟”整个文件夹拿走
function current_img_time()
{
    var sec=document.getElementById("sec")
        min=document.getElementById("min")
        hour=document.getElementById("hour")
    setInterval(function()
    {
        var curr=new Date()
        var a=curr.getHours()
        var b=curr.getMinutes()
        var c=curr.getSeconds()
        var millsec=curr.getMilliseconds()          //获取毫秒
        var t=((c+millsec/1000)/60)*360             //求秒加上毫秒/1000
            y=((b+c/60)/60)*360                     //求分必须加上秒/60
            u=((a+b/60)%12)/12*360                  //求时必须加上分/60
        sec.style.transform="rotate("+t+"deg)"
        min.style.transform="rotate("+y+"deg)"
        hour.style.transform="rotate("+u+"deg)"
    },1000)
}


//输出位于[min,max)的随机整数
//第一个形参写最小值；另一个是最大值。
//注意第一个要小于第二个数，而且分别min向上；max向下取整后，它们最少要相差1
function random_num(min,max)
{
    var b
    if(Math.ceil(min)<parseInt(max))
    {
        b=parseInt(Math.random()*(max-min)+min)
    }
    else
    {
        alert("第一个形参要小于第二个形参，而且分别min向上；max向下取整后，它们最少要相差1！")
        b=null
    }
    return b
}


// 随机选取[num1,num2)范围内的n个不同的随机数，且生成的随机数不重复
// 第一个参数n是想要生成的随机数的数量
// 第二、三个参数num1，num2是输出位于[num1,num2)的随机整数
function random_differentScope_num(n,num1,num2)
{
    if(num2-num1<n)
    {
        alert('生成的随机数的范围(num2-num1)必须大于等于想要生成的随机数的数量n！')
        return null
    }
    var arr=[]
    while(arr.length<n)
    {
        var leng=random_num(num1,num2)
        if(arr.indexOf(leng)==-1)
        {
            arr.push(leng)
        }
    }
    return arr
}


// 输出针对于原字符串的随机生成的指定长度的字符串。输出的字符串的顺序任意，但是不可以重复取原字符串的同一个位置的字符
// 第一个参数是原始字符串，比如可以设str='qwertyuiopasdfghjklzxcvbnm1234567890_QWERTYUIOPASDFGHJKLZXCVBNM'
function random_string(str)
{
    var leng=random_num(0,str.length)
    var arr=random_differentScope_num(leng,0,str.length)
    var arrstr=[]
    for(var i=0;i<arr.length;i++)
    {
        arrstr[i]=str[arr[i]]
    }
    newstr=arrstr.join('')
    return newstr
}


//输出原数列的num长度的，位于[min,max)区间内的随机数列
//num，min，max都是数字，num是所需单组数列长度
//数列的元素个数要小于最大值与最小值的差
// 用到了random_num()函数以及indexOf_array()函数
function numGroup_noRepeat(num,min,max)
{
    var t=[]
    var a
    if(parseInt(max)-parseInt(min)<=num)
    {
        alert("数列的元素个数要小于最大值与最小值的差")
        return t=null
    }
    /** 第一种方式*/
    ////////////////
    // for(var i=0;i<num;i++)
    // {
    //     a=random_num(parseInt(min),parseInt(max))
    //     if(indexOf_array(a,t)==-1)
    //     {
    //         t.push(a)
    //     }
    //     else
    //     {
    //         i--         //如果不i--，会导致输出空数值，i--目的是把输出空数值时的计数器减掉
    //     }
    // }
    ///////////////
    /**第二种 */
    for(var i=0;t.length<num;i++)           //强制使得数列t的长度为num，这也为我提供了一种新思路，for循环中不一定所有表达式的变量都一样还有，数列的push属性也需要重点关注！
    {
        a=random_num(parseInt(min),parseInt(max))
        // if(num)
        if(indexOf_array(a,t)==-1)
        {
            t.push(a)
        }
    }
    ///////////////
    for(var j=0;j<num;j++)
    {
        if(t[j]<10&&t[j]>=0)
        {
            t[j]='0'+t[j]
        }
    }
    return t
}


// 输出删除某一元素后，按原顺序输出原数组剩余的部分
// 第一个形参是改变后的数组；另一个是想要删除的元素在原数组中的序号。
// num要小于原数组的长度
// splice,substr,substring要记住!
function re_array(arr,num)
{
    var n=[]
    if(num>=arr.length)
    {
        alert("删除的序号应该对应原数组的序号！")
    }
    else
    {
        for(var j=0;j<arr.length;j++)
        {
            if(j!=num)
            {
                n.push(arr[j])    
            }
        }
    }
    return n
}


//数组的大小排序。当rank='min_to_max'是由数值小到大排列；rank='max_to_min'是由大到小排列
//第一个形参是待排数列；第二个是排列方向
//第二个形参只能填字符串'min_to_max'（由小到大排列）或者'max_to_min'（由大到小排列）
//用到了re_array()函数和seek_extreme_value()，还有indexOf_array()函数
function array_rank(array,rank)
{
    var n=[]
    var position
    var m=array
    if(rank=='min_to_max')
    {
        for(i=0;i<array.length;i++)    //注意：此处不可以是array.length，因为array的长度随着不断被剪切而减小，所以要设一个m=array，来代替array被剪切
        {
            m=re_array(m,position)
            n.push(seek_extreme_value(m,'min'))
            position=indexOf_array(seek_extreme_value(m,'min'),m)
        }
    }
    else if(rank=='max_to_min')
    {
        for(i=0;i<array.length;i++)    //注意：此处不可以是array.length，因为array的长度随着不断被剪切而减小，所以要设一个m=array，来代替array被剪切
        {
            m=re_array(m,position)
            n.push(seek_extreme_value(m,'max'))
            position=indexOf_array(seek_extreme_value(m,'max'),m)
        }
    }
    else
    {
        alert("第二个形参需要填字符串'min_to_max'（由小到大排列）或者'max_to_min'（由大到小排列）！")
    }
    return n
}


//数组的大小排序。当rank='min_to_max'是由数值小到大排列；rank='max_to_min'是由大到小排列
//第一个形参是待排数列；第二个是排列方向
//第二个形参只能填字符串'min_to_max'（由小到大排列）或者'max_to_min'（由大到小排列）
//冒泡排序法，十分重要，理解原理！！！
function bubble_sort(array,rank)
{
    if(rank=='max_to_min')
    {
        for(var i=0;i<array.length-1;i++)       //也可以不减1
        {
            for(var j=0;j<array.length-i;j++)   //也可以不减i,减1或者不减都行
            {
                if(array[j]<array[j+1])         //小于号是从大到小排列，如果是大于号的话，那么就是从小到大排列
                {
                    var temp=array[j]
                    array[j]=array[j+1]
                    array[j+1]=temp
                }
            }
        }
    }
    else if(rank=='min_to_max')
    {
        for(var i=0;i<array.length-1;i++)       //也可以不减1
        {
            for(var j=0;j<array.length-i;j++)   //也可以不减i,减1或者不减都行
            {
                if(array[j]>array[j+1])         //小于号是从大到小排列，如果是大于号的话，那么就是从小到大排列
                {
                    var temp=array[j]
                    array[j]=array[j+1]
                    array[j+1]=temp
                }
            }
        }
    }
    else
    {
        alert("rank只能是字符串'max_to_min'或者'min_to_max'")
    }
    return array
}


//实现阻塞页面time毫秒的时间
// time的单位是毫秒，而且time是数值形式
function delay(time)
{
    var current=new Date()
    for(;new Date()-current<time;)  //定义current之后，是不会变的；而new Date()是不断变的,最后一个表达式不用写任何东西，因为时间自己一直不断跳，所以忽略
    {}
}


// 对应搭配，得到的数列第一项是两个数列可以对应上的个数；第二项是返回可以对应上的概率
//两个形参是长度一样的数组
//两个数列必须长度一致
function matchObj(arr1,arr2)
{
    var j=0
    var p
    var array=[]
    if(a.length==b.length)
    {
        for(i=0;i<arr1.length;i++)
        {
            if(arr1[i]==arr2[i])
            {
                j++
            }
        }
        p=j/a.length    //对应的概率
        array=[j,p]
    }
    else
    {
        alert("输入的两个数列必须长度相同！")
        array=null
    }
    return array
}


//降成1维数组
//形参是原数组
// 注：只能降1层
// function one_dimension_reduce(arr)
// {
//     var mid=[]
//     for(var i=0;i<arr.length;i++)
//     {
//         mid=mid.concat(arr[i])  //注：必须是：数组.concat(内容)；而不是数组.concat（数组，内容）
//     }
//     return mid
// }
function one_dimension_reduce(arr)
{
    while(arr.some(function(item){
        return Array.isArray(item)
    }))
    {
        arr=[].concat(...arr)
    }
    return arr
}
// 也可以是arr.flat(Infinity)
// 或者
// function one_dimension_reduce(arr)
// {
//     return arr.toString().split(',').map(function(i){return i*1})
// }



//把原来数列，升维成二维矩阵，rowNumber是行数
//arr是原始数列，rowNumber是矩阵行数
function upgrade_dimension(arr,rowNumber)
{
    var store=arr.length             //随着程序的进行，arr.length会不断变化，因此需要进行储存变量
    if(arr.length%rowNumber==0)
    {
        var dd=[],pp=[]
        for(var i=0;i<rowNumber;i++)
        {
            for(var j=0;j<(store/rowNumber);j++)
            {
                dd.push(arr[0])
                arr=re_array(arr,0)
            }
            pp.push(dd)
            dd=[]
        }
        return pp
    }
    else
    {
        alert("如果想要变成矩阵，需要arr.length%rowNumber=0！")
        return arr
    }
}


// 将原始数组重新按照顺序排列成矩阵
// 第一个参数是原始数列；第二个参数是按照什么顺序排列，只能填字符串'min_to_max'（由小到大排列）或者'max_to_min'（由大到小排列）
// 第三个参数是要变成的新的矩阵的行数
// 返回一个新矩阵
function rerankArr_to_matrix(olrr,rank,new_rowNumber)
{
    var array=array_rank(one_dimension_reduce(olrr),rank)
    var newMatrix=upgrade_dimension(array,new_rowNumber)
    return newMatrix
}


//将原来的字符串中的一种符号改成另一种符号
//可以利用.split(olsymbol).join(_symbol)，继续拓展此函数，以达到改其他符号的效果
//olsymbol，和_symbol都是字符串，如果要去掉空格，那么_symbol=''即可
// ！！！注意，这里olsymbol也可以是正则表达式，从而实现将所有的某种（类）符号（字符）全部转化成另外一种（个）符号（字符）//
function changeStr(str,olsymbol,_symbol)
{
    return str.split(olsymbol).join(_symbol)
}


// 轮播图常用，elements是待移动元素，target是目标位置（数字形式），stepnum是单次变化的距离（数字形式）
// 向左缓慢移动(左则stepnum是正)
/**********                          *** */
function anmiate(elements,target,stepnum) 
{
    clearInterval(elements.timer)
    //为了指向dom对象里面，所以用到对象elements.timer，timer可以随便改。
    elements.timer = setInterval(function()
    {
        // 判断初始值和 目标值 
        var current = elements.offsetLeft
        var step=stepnum
        // step = current > target? -step : step        //这样当鼠标移动到相应位置的时候，会匀速移动
        step=current>target? -step:step//这样当鼠标移动到相应位置的时候，会快速移动
        if(current != target)
        {
            elements.style.left= current + step + "px"
        }
        else
        {
            clearInterval(elements.timer)
        }
    },16)
}


/**
 *        最终实现元素id转class或者class转id
 * @param {*} element 是打算变化id名或者class名的元素
 * @param {*} name1   name1是原始的id名或者class名，注意是字符串
 * @param {*} name2   name2是打算改变成的id名或者class名，注意是字符串
 * @param {*} str     改变之后id名或者class名，注意是字符串
 */
function id_class(element,name1,name2,str)
{
    if((name1=='id'&&name2=='class')||(name2=='id'&&name1=='class'))
    {
        element[0].removeAttribute(name1)  //注意是类数组，所以需要加序号
        //element[0].className=''           也可以这么消去classname，注意仅仅适用于class
        element[0].setAttribute(name2,str)
    }
    else
    {
        alert('name1和name2只能是"id"或者"class"字符串，且不相同！')
    }
}



/**                 对象常用                    */
//添加新对象的时候，如：obj={};加入：a:3；此时需要用到obj.a=3;如果是循环加入，则需要用到： obj[array[i]]=内容 。
// 第一对，对象值存数组
// 提取对象中的所有信息，并且储存在数组中，因此返回值是数组
// obj是待提取的对象
function get_objvalue_information_arr(obj)
{
    var arr=[]
    for(var key in obj)
    {
        arr.push(obj[key])
    }
    return arr
}
/*
    // 升级版对象值存数组，但是有局限性
    // function get_objvalue_information_arr(obj)
    // {
    //     var _slice=[].slice;     //因为对象没有slice这个方法，它借调数组中的slice方法方法，能像操作数组那样，操作对象，对对象元素进行截取
    //     var objArr=_slice.call(obj);
    //     return objArr
    // }
    ////输入对象样式：对象名必须是0，1，2，3，4这种类型的
        // var obje = 
        // {
        //     0:'qian',
        //     1:'long',
        //     2:'chu',
        //     3:'tian',
        //     4:'io',
        //     length:4    //必须注明长度，输出的时候长度是多长就输出多长
        // }

    //////////////////////var a = [].slice; console.log(a); //ƒ slice() { [native code] }
*/


// 第二队，对象名存数组
// 提取对象中对象名储存在数组中
// 并返回这个数组
// 利用此函数可以求取对象内的内容的长度：get_object_information_arr(obj).length
// obj是待提取的对象
function get_object_information_arr(obj)
{
    var arr=[]
    for(var key in obj)
    {
        arr.push(key)
    }
    return arr
}

// 第三对，找名
// 寻找对象中是否存在这个对象名
// 如果存在，那么就返回该属性名，否则返回undefined
function search_object(obj,subject)
{
    var k=undefined
    var wait=subject
    for(var key in obj)
    {
        if(wait==key)
        {
            k=key
        }
    }
    return k
}

// 第四对，找值
// 寻找对象中是否存在这个对象值
// 如果存在，那么就返回该属性名，否则返回undefined
function search_objValue(obj,obj_value)
{
    var k=undefined
    var wait=obj_value
    for(var key in obj)
    {
        if(wait==obj[key])
        {
            k=wait
        }
    }
    return k
}

// 第五对，由值找名
// 已知属性值，寻求属性名
// obj是待查找对象，objvalue是待查找属性值
// 返回对应属性名，否则返回undefined
function value_search_object(obj,objvalue)
{
    var k=null
    var wait=objvalue
    for(var key in obj)
    {
        if(wait==obj[key])
        {
            k=key
        }
    }
    return k
}

// 数组中存储的对象的对象值转成矩阵
// 输入的是一个由对象构成的数组
function getobjValue_to_matrix(arr_obj)
{
    if(arr_obj.length==1)
    {
        return get_objvalue_information_arr(arr_obj[0])
    }
    else if(arr_obj.length<1)
    {
        alert('输入的数组是空！')
        return null
    }
    else
    {
        var arr=init_matrix(arr_obj.length)//原始数组长度
        var object_name_arr=get_object_information_arr(arr_obj[0])//获取数组中的每一项的对象的个数
        for(var i=0;i<arr_obj.length;i++)
        {
            var objValue_arr=get_objvalue_information_arr(arr_obj[i])//获取数组中的每一项的对象的对象值
            for(var j=0;j<object_name_arr.length;j++)
            {
                arr[i].push(objValue_arr[j])
            }
        }
        return arr
    }
}


// 寻找字符串中的所有字符，存储到对象里面，对象值是出现的次数
// str是字符串
function seek_num_to_obj(str)
{
    var obj={}
    for(var i=0;i<str.length;i++)
    {
        if(obj[str[i]]) //由于查找里面没有出现过的对象，会显示undefined，这时进入else，给这个没有出现过的对象数量加1；否则直接在原有数量上继续加1
        {
            obj[str[i]]=obj[str[i]]+1
        }
        else
        {
            obj[str[i]]=1       //给每一个没出现过的对象值赋1
        }
    }
    return obj
}


// 向数组的最小值中插入随机数
// arr是原始数组，num是插入数字次数
// 返回新数组
// 瀑布流常用
function insert_min_value(arr,num)
{
    for(var i=0;i<num;i++)
    {
        var t=random_num(1,30)
        var y=seek_extreme_value(arr,'min')
        arr[arr.indexOf(y)] += t
    }
    return(arr)
}


// 意思是寻求到页面顶部的距离，以及左边的距离，随着滚动而不断改变
// 应用的时候，需要写scroll().top或者scroll().left
function scroll() 
{
    return {
        top:window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0,               //用来兼容IE
        left:window.pageYOffset || document.documentElement.scrollLeft || document.body.scrollLeft || 0             //用来兼容IE
    }
}


// 意思是寻求整屏的宽度，以及整屏的高度，随着滚动而不断改变
// 应用的时候，需要写client().width或者client().height
function client() 
{
    return {
        width:window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth || 0,
        height:window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight || 0
    }
}


// 初始化一个num行的矩阵
function init_matrix(num)
{
    var matrix=[]
    for(var i=0;i<num;i++)
    {
        matrix[i]=[]
    }
    return matrix
}


// 判断数组（不要求是矩阵）中的每一项是否都是数字类型的，主要用于判断是否是矩阵或者向量的函数
// 是的话输出true；不受输出false
function isNumber_array(matrix)
{
    var flag=true
    if(!matrix[0])
    {
        return !flag
    }
    for(var i=0;i<matrix.length;i++)
    {
        if(matrix[i].length==undefined)
        {
            for(var k=0;k<matrix.length;k++)
            {
                if(typeof matrix[k]=="object"||typeof matrix[k]=="string"||(matrix[k]!=0&&!matrix[k]==true))    //注意！nan永远不等于nan
                {
                    return false
                }
            }
        }
        else
        {
            for(var j=0;j<matrix[i].length;j++)
            {
                if(typeof matrix[i][j]=="object"||typeof matrix[i][j]=="string"||matrix[i][j]==NaN)
                {
                    return false
                }
            }
        }
    }
    return flag
}


// 对矩阵或者数组中的不是数字类型的项进行转化，如果转化成NaN，那么直接赋值为0
function MatrixArray_add_zero(matrix)
{
    if(!isNumber_array(matrix))
    {
        // 初步判断未知矩阵的行数列数
        // 但是不能用这个程序段直接判断是否是矩阵或者向量，否则会有bug
        var arr
        if(matrix[0][1]==undefined&&(typeof matrix[0])=="object")
        {
            arr= [matrix.length,1]
        }
        else if((typeof matrix[0])&&matrix[0][1]==undefined)
        {
            arr= [1,matrix.length]
        }
        else
        {
            arr= [matrix.length,matrix[0].length]
        }
        //这里，arr[0]是行数，arr[1]是列数
        if(arr[0]!=1)   // 即所输入的是矩阵的时候
        {
            for(var i=0;i<arr[0];i++)
            {
                for(var j=0;j<arr[1];j++)
                {
                    if((typeof matrix[i][j]*1)!="number")
                    {
                        matrix[i][j]=matrix[i][j]*1
                    }
                    if((matrix[i][j]!=0&&!matrix[i][j]==true))
                    {
                        matrix[i][j]=0
                    }
                }
            }
        }
        else            // 即所输入的是向量的时候
        {
            for(var k=0;k<matrix.length;k++)
            {
                if((typeof matrix[k]*1)!="number")
                {
                    matrix[k]=matrix[k]*1
                }
                if((matrix[k]!=0&&!matrix[k]==true))
                {
                    matrix[k]=0
                }
            }
        }
    }
    return matrix
}


// 判断是否是数字型矩阵或者向量
// 是的话返回true，不是的话返回false
function isMatrix_or_Array(matrix)
{
    var arr
    // 初步判断未知矩阵的行数列数
    // 但是不能用这个程序段直接判断是否是矩阵或者向量，否则会有bug
    if(matrix[0][1]==undefined&&(typeof matrix[0])=="object")
    {
        arr= [matrix.length,1]
    }
    else if((typeof matrix[0])&&matrix[0][1]==undefined)
    {
        arr= [1,matrix.length]
    }
    else
    {
        arr= [matrix.length,matrix[0].length]
    }
    //这里，arr[0]是行数，arr[1]是列数
    var flag=true
    if(one_dimension_reduce(one_dimension_reduce(matrix)).length!=arr[0]*arr[1])
    {
        return !flag
    }
    var key=matrix[0].length
    if(isNumber_array(matrix)==false)
    {
        return !flag
    }
    else
    {
        for(var i=0;i<arr[0];i++)            //i是矩阵的行
        {
            if(matrix[i].length!=key)
            {
                return !flag
            }
        }
        return flag
    }
}


// 求矩阵的行数列数
// 返回值是数组：[行数，列数]
function matrix_size(matrix)
{
    if(isMatrix_or_Array(matrix)==true)
    {
        if(matrix[0][1]==undefined&&(typeof matrix[0])=="object")
        {
            return [matrix.length,1]
        }
        else if((typeof matrix[0])&&matrix[0][1]==undefined)
        {
            return [1,matrix.length]
        }
        else
        {
            return [matrix.length,matrix[0].length]
        }
    }
    else
    {
        alert('输入的不是数字型矩阵或者向量')
        return undefined
    }
}


// 求得矩阵和向量的转置,这里matrix行数列数任意
// 注意列向量的表达方式是[[num1],[num2],[num3],...]；行向量表达方式是[num1,num2,num3,...]
// 注意矩阵表达方式，matrix[行序号][列序号]；
// 如果表达是matrix[number]，代表第number行的所有元素
function matrix_transpose(matrix)
{
    if(matrix_size(matrix)==undefined)
    {
        alert('输入不是矩阵！')
        return undefined
    }
    else if(matrix_size(matrix)[0]==1)                    //matrix是行向量，用来转化成列向量
    {
        var column_vector=[]
        for(var i=0;i<matrix.length;i++)
        {
            var y=matrix[i].toString().split(',');
            column_vector.push(y)
        }
        for(var j=0;j<column_vector.length;j++)
        {
            column_vector[j][0]=column_vector[j][0]*1      //将字符串转化成数字类型
        }
        return column_vector
    }
    else if(matrix_size(matrix)[1]==1)                     //matrix是列向量，用来转化成行向量
    {
        var row_vector=[]
        for(var i=0;i<matrix.length;i++)
        {
            row_vector.push(matrix[i][0])
        }
        return row_vector    
    }
    else                                            //matrix除了行向量和列向量之外的矩阵都可以用
    {
        var result=[]
        for(var i=0;i<matrix[0].length;i++)
        {
            var row=[]                              //每次出循环都初始化一次
            for(var j=0;j<matrix.length;j++)
            {
                row.push(matrix[j][i])              //把对应的每一列的值取出来单独放到矩阵中，而不是局限于单个值的互换
            }
            result.push(row)                        //确认行之后，将其挤入新数组中，使得原来列成为行
        }
        return result
    }
}
// 简陋版矩阵转置
// function matrix_transpose(matrix)                       //这里matrix必须是方阵
// {
//     for(var i=0;i<matrix.length;i++)
//     {
//         for(var j=i;j<matrix[i].length;j++)
//         {
//             var temp=matrix[i][j]
//             matrix[i][j]=matrix[j][i]
//             matrix[j][i]=temp
//         }
//     }
//     return matrix
// }
/** */


// 矩阵整体旋转90°（可以应用于图像变换等领域）
// 输入变量是一个矩阵
function rot_90deg_right(matrix)
{
    return matrix_transpose(matrix.reverse())
}


// 行向量求内积，相当于vec1(转置)*vec2，即对应项相乘再整体求和
// 不适用于内部含有字符串的向量，也不适用于缺项的向量
//vec1和vec2是两个1维数组
function vector_inner_product(vec1,vec2)   
{
    if(matrix_size(vec1)[0]==1&&matrix_size(vec2)[0]==1&&(matrix_size(vec1)[1]==matrix_size(vec2)[1]))
    {
        var sum=0
        for(var i=0;i<vec1.length;i++)
        {
            sum=sum+vec1[i]*vec2[i]
        }
        return sum
    }
    else
    {
        alert('此函数的形式参数是两个1维的相同长度的行向量！')
        return undefined
    }
}


// 矩阵相乘
// matrix1和matrix2是两个矩阵，两个向量也行
// 不适用于内部含有字符串的矩阵，也不适用于缺项的矩阵
// matrix1的列数要与matrix2的行数相等！
function multiple_matrix(matrix1,matrix2) 
{
    if(matrix_size(matrix1)[1]==matrix_size(matrix2)[0])
    {
        var transposed=matrix_transpose(matrix2)
        if(matrix1[1][0]==undefined&&matrix2[0][1]==undefined)
        {
            return vector_inner_product(matrix1,transposed)
        }
        else
        {
            var temp
            var result=[]
            for(var i=0;i<matrix1.length;i++)
            {
                var row=[]
                for(var j=0;j<transposed.length;j++)
                {
                    temp=vector_inner_product(matrix1[i],transposed[j])
                    row.push(temp)
                }
                result.push(row)
            }
            return result
        }
    }
    else
    {
        alert("第一个矩阵或向量的列数要等于被乘矩阵或向量的行数！")
        return null
    }
}


// 求取矩阵的秩，注意：这是残次品！
// 输入矩阵，输出秩
function matrix_rank(matrix)
{
    var arr=matrix_size(matrix)
    var newma=init_matrix(arr[0])
    newma[0]=matrix[0]
    for(var i=1;i<arr[0];i++)
    {
        var flag=matrix[i][i-1]/matrix[i-1][i-1]
        for(var j=i-1;j<arr[1];j++)
        {
            newma[i][j]=matrix[i][j]-matrix[i-1][j]*flag
        }
    }
    console.log(matrix);
    console.log(!newma[2][0]);
    for(var i=0;i<arr[0];i++)
    {
        for(var j=0;j<arr[1];j++)
        {
            if(!newma[i][j])
            {
                newma[i][j]=0
            }
        }
    }
    console.log(newma);
    // newma[empty]
    for(var i=0;i<Math.min.apply([],matrix_size(newma));i++)
    {
        var k
        if(newma[i][i]==0)
        {
            k=i-1
            break
        }
        else
        {
            k=i
        }
    }
    return i
}




// 去除首尾空格，留存中间的字符串
// 扩展：取两个相同或者不同符号之间的字符串的内容
// 也可以用str.trim()去掉首尾空格
function remove_head_tail_space(str)
{
    var str1=''
    var one,two         //分别存放第一个不是空格的位次和最后一个不是空格的位次
    var newstr=''
    for(var i=0;i<str.length;i++)
    {
        if(str[i]!=' ')
        {
            one=i
            break
        }
    }
    str1=str.split('').reverse().join('')   //将字符串反转
    for(var j=0;j<str1.length;j++)
    {
        if(str1[j]!=' ')
        {
            two=j
            break
        }
    }
    for(var k=one;k<str.length-two;k++)     //也可以用slice命令代替，遇到无法判断的就引入第三变量帮助判断
    {
        newstr=newstr+str[k]
    }
    return newstr
}
// var str='   hdiwj efyjwe pj ew   '
// var str1=''
// var flag=false
// var index
// for(var i=0;i<str.length;i++)
// {
//     if(str[i]==' '&&!flag)
//     {
//         flag=false
//         index=i
//     }
//     else
//     {
//         flag=true
//         str1+=str[i]
//     }
// }
// console.log(str1);
/**     上面的是去掉前面的空格，是一个重要的编程经验，当出现变成问题的时候，可以加一个flag      */


//定时器，定时有限时间
// n是数字，time也是数字，time单位是毫秒，因此这个定时器定义的是(n*time)毫秒
function myTimer(n,time)
{
    n--
    var t=setTimeout(function()
    {
        console.log(n);
        if(n>0)
        {
            my(n,time)
        }
        else
        {
            clearTimeout(t)
        }
    },time)
}


// 获取cookie值，cname是名字，cvalue是值，day是指过期时间
// 用open with live sever打开
function setCookie(cname , cvalue, day) {
    var d = new Date()
    d.setTime(d.getTime() + day*(1000*60*60*24))
    document.cookie = cname +"="+cvalue+";expires="+d.toUTCString()+";path=/"
}
// cookie常用
// 例子：t='zhan=战国; hisd=279; si=29'，输入：search_value(t,'zhan')；那么输出：'战国'
// 返回字符串
function search_value(str,key)
{
    var idx
    var arr=str.split(';')
    for(var i=0;i<arr.length;i++)
    {
        if(arr[i].indexOf(key)!=-1)
        {
            idx=i
            break
        }
    }
    var newarr=arr[idx]
    var newstr=''
    for(var i=newarr.indexOf('=')+1;i<newarr.length;i++)
    {
        newstr=newstr+newarr[i]
    }
    return newstr
}


// 将目标字符串中出现过的字符及其重复的数量存到对象中
function str_repeat_num_in_obj(str)
{
    var obj={}
    for(var i=0;i<str.length;i++)
    {
        if(!obj[str[i]])
        {
            obj[str[i]]=1
        }
        else
        {
            obj[str[i]]++
        }
    }
    return obj
}


// 将目标字符串中出现过的字符次数最多的返回出来
// 输入的形参是字符串类型
function find_Max_string(str)
{
    if(str.length==1)
    {
        return str
    }
    var obj=str_repeat_num_in_obj(str)
    // console.log(Ma);
    var arr=get_objvalue_information_arr(obj)
    var key=value_search_object(obj,Math.max.apply([],arr))
    return key
}


// 字符串比较，判断 str1 能不能由 str2 里面的字符构成。而且 str2 中的每个字符只能在 str1 中使用一次。
// 本质：确定str1的字符串的每一个字符是不是str2字符串的子集。
// 也就是str1中的字符必须要在str2中出现，并且str1中的字符的频次小于str2中字符出现的频次
// str1能由str2里面的字符构成就返回true，否则是false
// 方法一，比较完一个就干掉一个
function str_compare(str1, str2) 
{
    for(var i=0; i<str1.length;i++)
    {
        var result = str1[i]
        if(str2.indexOf(result)==-1)
        {
            return false;
        }
        str2 = str2.replace(result,'');   // 比较完一个就干掉一个
    }
    return true;
}
/*  方法二，此种方法比较麻烦
function str_compare(str1,str2)
{
    var flag
    // 将a,b中的字符数目存储到对象中
    var obj1=str_repeat_num_in_obj(str1)
    var obj2=str_repeat_num_in_obj(str2)
    // a、b名提取出来到数组里面
    var arr_str1=get_object_information_arr(obj1)
    var arr_str2=get_object_information_arr(obj2)

    if(arr_str1.length>arr_str2.length)
    {
        flag=false
        return flag
    }
    else
    {
        for(var i=0;i<arr_str1.length;i++)
        {
            if(arr_str2.indexOf(arr_str1[i])!=-1&&obj2[arr_str1[i]]>=obj1[arr_str1[i]])
            {
                flag=true
            }
            else
            {
                flag=false
                break
            }
        }
        return flag
    }
}
*/


// 取出字符串中所有数字
// 也可以利用正则表达式，更加简便而且用途更广范，利用上面的changeStr(str,olsymbol,_symbol)函数。
// 返回的是字符串
function take_All_number(str)
{
    var str1=''
    for(var i=0;i<str.length;i++)
    {
        if(str[i]*1<10)
        {
            str1+=str[i]
        }
    }
    return str1
}


// 后台传输数据专用函数，但是没有解决跨域问题
// 解决跨域问题需要用到jsonP()函数，或者改Live Server里的扩展设置中的enable项、baseUri项、proxyUri项的值
// _url是接口URL，例如：http://101.43.3.225:9506/api/site/get_index的接口后面的所有东西，即"/api/site/get_index"
// _method是请求方式，'get'或者'post'
// data是"id=值"（用location.search或者location.hash获取）  走详情页的时候会用到；首页的时候，""
// callback应该填回调函数：   function(t){函数体内部；t是所有的后台发送的数据，JSON.parse(t)，转发为对象（熟知的，能直接操作的）}
function ajax(_url,_method,data,callback)
{
    var _prfx='/api'
    _url=_prfx+_url
    var xhr = new XMLHttpRequest()
    if(_method == "get")
    {
        _url = _url+"?"+data
    }
    xhr.open(_method,_url)
    if(_method == "post")
    {
        xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded")
        // 发送数据
        xhr.send(data)
    }
    else
    {
        xhr.send(null)
    }
    xhr.onreadystatechange = function() {
        if(xhr.readyState == 4 && xhr.status == 200) {
            // console.log(xhr.response)
            callback(xhr.response)
        }
    }
}

// 利用promise写法写成的ajax函数
const new_promise_ajax=function(url,type,data){
    const pro=new Promise(function(res,rej){
        // 1、初始化
        let xHTTP=new XMLHttpRequest()
        xHTTP.open(type,url)
        xHTTP.responseType='json'
        xHTTP.setRequestHeader('Accept','application/json')
        xHTTP.send(data)
        xHTTP.onreadystatechange=function(){
            if(this.readyState!==4)
            {
                return
            }
            if(this.status===200)
            {
                // 请求成功
                res(this.response)
            }
            else
            {
                // 请求失败
                rej(new Error(this.statusText))
            }
        }
    })
    return pro
}
    // // // 模板
    // // new_promise_ajax().then(res=>{
    // //     // 成功的值，接口请求成功返回的内容
    // //     console.log(res)
    // //     }).catch(err=>{
    // //         // 失败的值，接口请求失败返回的内容
    // //         console.log(err);
    // //     })
    // // 比如：
    // new_promise_ajax('http://wthrcdn.etouch.cn/weather_mini?city=南京','get').then(res=>{
    //     console.log(res);
    // })


/**
 * 高亮显示
 * @param {*} a 对象集合，需要清除class类的对象（或者标签）
 * @param {*} b 对象（或者标签）当前赋值class
 * @param {*} c 不传参，默认active，这里以后高亮事件的class名就是"active"
 */
// 实现排他功能
function highlight(a,b,c="active") {
    for(var j=0;j<a.length;j++) {
        a[j].className = ""
    }
    b.className = c
}
// 升级版的排他函数
// function highlight1(a, b, c) 
// {
//     for (var j = 0; j < a.length; j++) {
//         a[j].classList.remove(c);
//     }
//     b.classList.add(c);
// }


// 寻找因数
function factor(num)
{
    if(num<1||num-parseInt(num)!=0)
    {
        alert('输入数字必须是大于1的整数！')
        return undefined
    }
    var arr=[]
    for(var i=1;i<=num;i++)
    {
        if(num%i==0)
        {
            arr.push(i)
        }
    }
    return arr
}


// 利用弹窗进行跳转其他网站操作，点击确认进行跳转，点击取消则取消跳转
// 第一个参数what是点击的内容，即Class名或者ID名；第二个参数是跳转的地址的字符串形式
// 例如：可以写成jumpTo($('.ww')[0],"../js淘宝/js淘宝 copy 2.html")
// 上面的a标签可以写成<a href="javascript:;">内容</a>或者<a href="#">内容</a>，但是href如果是#，那么会向地址传参；如果是javascript:;就不会传参。当然，这两种的效果一样。
function jumpTo(what,local)
{
    what.onclick=function(ee)
    {
        if(!confirm('确认进入网站： '+local+" 吗?"))
        {
            ee.preventDefault()
        }
        else
        {
            location.href=local
        }
    // // 这么写也可以！
        // what.onclick=function(ee)
        // {
        //     if(!confirm('确认进入网站： '+local+" 吗?"))
        //     {
        //        ee.preventDefault()
        //     }
        //     what.href=local
        //     what.onclick
        // }
    }
}


// 寻找公共前缀或者公共后缀
// 输入的第一个参数是数组；第二个参数是字符串，只能填'pre'代表前缀；或者'next'代表后缀
function find_prefix(arr,preOrnext)
{
    if(preOrnext=='pre')                 //pre代表前缀
    {
        if(arr.length<=1)
        {
            alert("输入数组的长度必须大于1！")
            return arr[0]
        }
        var init_str=arr[0]
        var k
        var newarr=[]
        for(var i=1;i<arr.length;i++)
        {
            for(var j=0;j<arr[i].length;j++)
            {
                if(init_str[j]!=arr[i][j])
                {
                    k=j-1
                    break
                }
                else
                {
                    k=j
                }
            }
            newarr.push(k)
        }
        var min=seek_extreme_value(newarr,'min')
        if(min<0)
        {
            alert("没有公共前缀！")
            return null
        }
        var str=init_str.slice(0,min+1)
        return str
    }
    else if(preOrnext=='next')               //寻找后缀
    {
        var array=[]
        for(var i=0;i<arr.length;i++)
        {
            array.push(arr[i].split('').reverse().join(''))
        }
        // console.log(array);
        var init_str=array[0]
        var k
        var newarr=[]
        for(var i=1;i<array.length;i++)
        {
            for(var j=0;j<array[i].length;j++)
            {
                if(init_str[j]!=array[i][j])
                {
                    k=j-1
                    break
                }
                else
                {
                    k=j
                }
            }
            newarr.push(k)
        }
        var min=seek_extreme_value(newarr,'min')
        if(min<0)
        {
            alert("没有公共后缀！")
            return null
        }
        var str=init_str.slice(0,min+1).split('').reverse().join('')
        return str
    }
    else
    {
        alert("第二个参数只能填'pre'代表前缀；或者'next'代表后缀")
    }
}


// 改变对应对象。
// 其中第三个参数是所传参数，可以是单个值或者是单个数组。可有可无，如果是空，那么就是'' 。
// 第一个参数是原始等待改变指向的对象；第二个是新的等待指向的对象。
// 第四个参数是只能填字符串'singleParam'代表单个参数，或者'multiParam'代表多个参数(或数组)。
function changeDirect(olObj,newObj,param,sort)
{
    if(sort=='singleParam')
    {
        return olObj.call(newObj,param)
    }
    else if(sort=='multiParam')
    {
        return olObj.apply(newObj,param)
    }
    else
    {
        alert("第四个参数sort，只可以是'string'或者'array'类型！")
        return null
    }
}


// 二进制求加法
// 输入的两个值是二进制数字，不带0b前缀
function binary_arithmetic(num1,num2)
{
    var o1='0'+'b'+num1
    var o2='0'+'b'+num2
    return (o1*1+o2*1).toString(2)
}


// 类数组转化成数组
// 输入的变量是类数组形式
// 注意，类数组本质仍然是object；而数组虽然也会显示object，但是本质上是array
// 除了这种方法外，也可以用for循环或者for in循环，[...arr]等等
// 也可以用call，用法： [].slice.call(array_like)
function obj_to_array(array_like)
{
    return [].concat.apply([],array_like)
}


// 数列打乱排序（随机排序）,需要用到双色球问题
// 输入是arr原数组
function array_random_arrange(arr)
{
    var randarr=[]
    var newarr=[]
    while(randarr.length<=6)
    {
        var l=random_num(0,arr.length)
        // console.log(arr.indexOf(u)==-1);
        if(randarr.indexOf(l)==-1)
        {
            randarr.push(l)
        }
    }
    for(var i=0;i<arr.length;i++)
    {
        newarr[randarr[i]]=arr[i]
    }
    return newarr
}


// 向原字符串中每隔相等的位置插入一个符号
// str是待操作的字符串，num是相隔的数值，symbol是插入的符号（字符串形式）
function insert_symbol(str,num,symbol)
{
    var newstr=''
    for(var i=0;i<str.length;i++)
    {
        if(i%num!=0||i==0)
        {
            newstr=newstr+str[i]
        }
        else
        {
            newstr=newstr+symbol+str[i]
        }
    }
    return newstr
}


// 利用递归函数
// 求阶乘
// 递归要想清楚变量是什么，通过找到变量，确认初始值，判断走出递归，做出递归
function factorial(num)
{
    var t
    if(num<1)
    {
        return 1
        // return fn(num)
    }
    else
    {
        t=num*factorial(num-1)
    }
    return t
}


// 斐波那契数字、数列（黄金分割数列）
// 这个性能好，相当于加count次，count相当于计数器
function Fibonacci_number(count,curr=1,next=1)
{
    if(count<=0)
    {
        return 0
    }
    else if(count==1)
    {
        return curr
    }
    else
    {
        return Fibonacci_number(count-1,next,curr+next)
    }
}
// function Fibonacci_number(num)// 斐波那契数字，但是性能不好，速度慢
// {
//     if(num<=0)
//     {
//         return 0
//     }
//     else if(num<=2&&num>0)
//     {
//         return 1
//     }
//     else
//     {
//         return Fibonacci_number(num-1)+Fibonacci_number(num-2)
//     }
// }


function Fibonacci_sequence(num)       // 斐波那契数列
{
    var arr=[]
    for(var i=0;i<=num;i++)
    {
        arr.push(Fibonacci_number(i))
    }
    return arr
}


/* JS中的转化：电脑与手机端页面转化PX大小 */
// res是原始的PS图片中待测量的px值
// 如：Font_size(750)
// 这里8732、2880可以根据给的ps图整体宽任意修改
function Font_size(res)
{
    let clientWidth = window.innerWidth||document.documentElement.clientWidth||document.body.clientWidth;
    let clientHeight=window.innerHeight||document.documentElement.clientHeight||document.body.clientHeight;
    if(!clientWidth) return;
    let size=0;
    if(clientWidth>clientHeight)
    {
        size=1*(clientWidth / 8732);//横屏的时候
    }
    else
    {
        size=1*(clientWidth / 2880);//竖屏的时候
    }
    return res*size
}


// 获取所需的id值
// name是指所需要的字符串前缀
// 比如./er.html?id=2&a=6&t=25，如果这个时候需要这里面的t参数，那么直接调用getUrl(t)就可以得到对应的值
function getUrl(name) {
    var reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)')
    // console.log(reg);
    var r = location.search.substring(1).match(reg)
    // console.log(r);
    if (r != null) return decodeURI(r[2])
    return null
}


// 深拷贝的函数
function deepCopy(e)
{
    var a
    // 1.判断是否是object基础类型  string,number,boolean,undefined
    if(typeof e==="object")
    {
        // 2.判断是不是数组
        if(Array.isArray(e))
        {
            a=[]
            for(var i in e)
            {
                a.push(deepCopy(e[i]))
            }
        }
        else if(e.constructor===Date)
        {
            // 3.是否是事件类型的object
            a=e
        }
        else if(e===null)
        {
            // 4.判断是否是空
            a=e
        }
        else if(e.constructor===RegExp)
        {
            // 5.判断是否是正则
            a=e
        }
        else if(e.constructor===Function)
        {
            // 6.判断是否是函数
            a=e
        }
        else
        {
            // 7.判断是否是对象
            var a={}
            for(var j in e)
            {
                a[j]=deepCopy(e[j])
            }
        }
    }
    else
    {
        a=e
    }
    return a
}



// 时间戳转换成标准时间
// e是标准时间戳
function formatDate(e) {
    var date = new Date(e);
    var year = date.getFullYear()
    var month=(date.getMonth()+1).toString().padStart(2,0)
    var day=(date.getDate()).toString().padStart(2,0)
    var hour=(date.getHours()).toString().padStart(2,0)
    var minute=(date.getMinutes()).toString().padStart(2,0)
    var second=(date.getSeconds()).toString().padStart(2,0)
    return `${year}年${month}月${day}日 ${hour}:${minute}:${second}`
}


// 下载为JSON格式文件
// obj是对象格式或者是数组格式，这里默认obj有name属性，并且下载成name属性的值的文件名
function download(obj) {
    var data = JSON.stringify(obj);
    console.log(data);
    let uri = 'data:text/csv;charset=utf-8,' + encodeURIComponent(data);
    let link = document.createElement("a");
    link.href = uri;
    link.download = `${obj.name}.json`;
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);
}

// 更改数据结构
// arr 是数组套对象的数据结构(id和children，children必须是[]或者里面也得有id或children)，返回的是value和children属性，如果children属性的值是[]，那么就删掉他
function ifChild(arr)
{
    arr.forEach(it =>
        {
            it.value = it.id;
            if (it.children.length != 0)
            {
                this.ifChild(it.children);
            }
            else
            {
                delete it.children; //children触发的是后面的级联
            }
        }
    );
}

// 平行结构更改为树形结构
// arrObj是数组套对象，可以与ifChild连用
//:
/* 例子
    var arrObj = [{
        id: 1,
        name: "北京市"
    }, {
        id: 2,
        name: "上海市"
    }, {
        id: 3,
        name: "江苏省"
    }, {
        id: 4,
        name: "黑龙江省"
    }, {
        id: 5,
        name: "辽宁省"
    }, {
        id: 101,
        parentID: 1,
        name: "东城区"
    }, {
        id: 301,
        parentID: 3,
        name: "南京市"
    }, {
        id: 302,
        parentID: 3,
        name: "苏州市"
    }, {
        id: 303,
        parentID: 3,
        name: "常州市"
    }, {
        id: 401,
        parentID: 4,
        name: "哈尔滨市"
    }, {
        id: 402,
        parentID: 4,
        name: "牡丹江市"
    }, {
        id: 501,
        parentID: 5,
        name: "沈阳市"
    }, {
        id: 502,
        parentID: 5,
        name: "大连市"
    }]
结果是:[
    {
        id: 1,
        name: "北京市",
        children: [
            {
                id: 101,
                parentID: 1,
                name: "东城区",
                children: []
            }
        ]
    },
    {
        id: 2,
        name: "上海市",
        children: []
    },
    {
        id: 3,
        name: "江苏省",
        children: [
            {
                id: 301,
                parentID: 3,
                name: "南京市",
                children: []
            },
            {
                id: 302,
                parentID: 3,
                name: "苏州市",
                children: []
            },
            {
                id: 303,
                parentID: 3,
                name: "常州市",
                children: []
            }
        ]
    },
    {
        id: 4,
        name: "黑龙江省",
        children: [
            {
                id: 401,
                parentID: 4,
                name: "哈尔滨市",
                children: []
            },
            {
                id: 402,
                parentID: 4,
                name: "牡丹江市",
                children: []
            }
        ]
    },
    {
        id: 5,
        name: "辽宁省",
        children: [
            {
                id: 501,
                parentID: 5,
                name: "沈阳市",
                children: []
            },
            {
                id: 502,
                parentID: 5,
                name: "大连市",
                children: []
            }
        ]
    }
]
*/
function treeConstructor(arrObj) {
    arrObj.forEach((item, idx) => {
        item.children = []
    })
    arrObj.forEach((it, idx) => {
        for (let i = 0; i < arrObj.length; i++) {
            if (it.parentID == arrObj[i].id) {
                arrObj[i].children.push(it)
            }
        }
    })
    for (let key in arrObj) {
        if (arrObj[key].parentID) {
            arrObj[key] = ''
        }
    }
    arrObj = arrObj.filter(it => {
        return it
    })
    return arrObj
}


/* RGB颜色转换为16进制 */
// 例：console.log(colorHex("rgb(52,83,139)"))		// #17f538
function colorHex(rgbStr) {
    //十六进制颜色值的正则表达式
    const reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/;
    if (/^(rgb|RGB)/.test(rgbStr)) {
        const aColor = rgbStr.replace(/(?:\(|\)|rgb|RGB)*/g, "").split(",");
        let strHex = "#";
        for (let i = 0; i < aColor.length; i++) {
            let hex = Number(aColor[i]).toString(16);
            if (hex === "0") {
                hex += hex;
            }
                strHex += hex;
        }
        if (strHex.length !== 7) {
            strHex = rgbStr;
        }
        return strHex;
    } else if (reg.test(rgbStr)) {
        const aNum = rgbStr.replace(/#/, "").split("");
        if (aNum.length === 6) {
            return rgbStr;
        } else if (aNum.length === 3) {
            let numHex = "#";
            for (let i = 0; i < aNum.length; i += 1) {
                numHex += (aNum[i] + aNum[i]);
            }
            return numHex;
        }
        } else {
            return rgbStr;
        }
};


/* 16进制颜色转换为RGB */
// 例：console.log(colorRgb("#34538b"))	// rgb(52,83,139)
function colorRgb (colorStr) {
    //十六进制颜色值的正则表达式
    var reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/;
    var sColor = colorStr.toLowerCase();
    if (sColor && reg.test(sColor)) {
        if (sColor.length === 4) {
            var sColorNew = "#";
            for (var i = 1; i < 4; i += 1) {
                sColorNew += sColor.slice(i, i + 1).concat(sColor.slice(i, i + 1));
            }
            sColor = sColorNew;
        }
        //处理六位的颜色值f
        var sColorChange = [];
        for (var i = 1; i < 7; i += 2) {
            sColorChange.push(parseInt("0x" + sColor.slice(i, i + 2)));
        }
        return "rgb(" + sColorChange.join(",") + ")";
    } else {
        return sColor;
    }
};


// 监听次数
// 例子： eventListenerTimes(div, 10, "click", () => console.log(22232323), true)
// eventListenerTimes(获取的dom元素, 监听次数, 监听事件, 监听的时候执行的回调函数, 立即监听并且算到监听次数中（默认false）)
function eventListenerTimes(dom, n, event, callbackFunction, immediate = false) {
    if(immediate) {
        callbackFunction();
        n--;
    }
    const times = () => {
        n--;
        callbackFunction();
        if (n <= 0) {
            dom.removeEventListener(event, times);
        }
    }
    dom.addEventListener(event, times);
}


// 将目标数组中出现过的重复对象拿出他们的id（唯一标识），并且存放在对应对象的数组中
// arr：目标数组
// objName：重复出现的对象
// arrID：数组对象中的唯一标识
function packRepeatItemsToObj(arr, objName, objID) {
    var obj = {}
    arr.forEach(it => {
        if (!obj[it[objName]]) {
            obj[it[objName]] = [it[objID]]
        } else {
            obj[it[objName]].push(it[objID])
        }
    });
    return obj
}
// var y = [{
//     aa: 12,
//     type: "ee",
//     id: "gu129e"
// }, {
//     aa: 122,
//     type: "ee",
//     id: "gu119e"
// }, {
//     aa: 102,
//     type: "ee",
//     id: "934eff"
// }, {
//     aa: 12,
//     type: "e5e",
//     id: "934e11f"
// }, {
//     aa: 12,
//     type: "ee",
//     id: "93fase"
// }, {
//     aa: 12,
//     type: "0ee",
//     id: "fds34e"
// }, {
//     aa: 12,
//     type: "ee",
//     id: "t53fde"
// }, ]
// console.log(packRepeatItemsToObj(y, "type", "id"));
/* 结果：
  var t = {
    ee: ["gu129e","gu119e","934eff","93fase","t53fde"],
    e5e: ["934e11f"],
    w0ee: ["fds34e"]
  }
*/

// 根据树状数据结构，根据其中id，寻找对应树状体
function findNameById(id, array) {
    for (const item of array) {
        if (item.id === id) {
            return item;
        }
        if (item.children && item.children.length > 0) {
            const foundInChildren = findNameById(id, item.children);
            if (foundInChildren) {
                return foundInChildren;
            }
        }
    }
    return null; // 返回 null 表示未找到匹配的名称
}
